package com.rose.springbootgeneratefile.api;

import com.rose.springbootgeneratefile.config.Configuration;
import com.rose.springbootgeneratefile.config.Context;
import com.rose.springbootgeneratefile.config.MergeConstants;
import com.rose.springbootgeneratefile.exception.ShellException;
import com.rose.springbootgeneratefile.internal.DefaultShellCallback;

import java.io.*;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.HashSet;
import java.util.List;
import java.util.Set;

public class MyBatisGenerator {
    /** The generated java files. */
    private List<GeneratedJavaFile> generatedJavaFiles;

    /** The generated xml files. */
    private List<GeneratedXmlFile> generatedXmlFiles;

    private Configuration configuration;

    private ShellCallback shellCallback;

    private Set<String> projects;

    public MyBatisGenerator(Configuration configuration){
        super();
        if (configuration == null) {
            throw new IllegalArgumentException("没有加载到配置文件"); //$NON-NLS-1$
        } else {
            this.configuration = configuration;
        }

        if (shellCallback == null) {
            this.shellCallback = new DefaultShellCallback(false);
        } else {
            this.shellCallback = shellCallback;
        }
        generatedJavaFiles = new ArrayList<GeneratedJavaFile>();
        generatedXmlFiles = new ArrayList<GeneratedXmlFile>();

        projects = new HashSet<String>();


    }

    public void generate(Set<String> contextIds,
                         Set<String> fullyQualifiedTableNames, boolean writeFiles) throws SQLException,
            IOException, InterruptedException {

        generatedJavaFiles.clear();
        generatedXmlFiles.clear();

        // calculate the contexts to run
        List<Context> contextsToRun;
        if (contextIds == null || contextIds.size() == 0) {
            contextsToRun = configuration.getContexts();
        } else {
            contextsToRun = new ArrayList<Context>();
            for (Context context : configuration.getContexts()) {
                if (contextIds.contains(context.getId())) {
                    contextsToRun.add(context);
                }
            }
        }




        for (Context context : contextsToRun) {
            context.introspectTables(fullyQualifiedTableNames);
        }


        for (Context context : contextsToRun) {
            context.generateFiles(generatedJavaFiles,generatedXmlFiles);
        }

        // now save the files
        if (writeFiles) {


//            for (GeneratedXmlFile gxf : generatedXmlFiles) {
//                projects.add(gxf.getTargetProject());
//                writeGeneratedXmlFile(gxf, callback);
//            }
//
            for (GeneratedJavaFile gjf : generatedJavaFiles) {
                projects.add(gjf.getTargetProject());
                writeGeneratedJavaFile(gjf);
            }
//
            for (String project : projects) {
                shellCallback.refreshProject(project);
            }
        }
    }

    private void writeGeneratedJavaFile(GeneratedJavaFile gjf)
            throws InterruptedException, IOException {
        File targetFile;
        String source;
        try {
            File directory = shellCallback.getDirectory(gjf.getTargetProject(), gjf.getTargetPackage());
            targetFile = new File(directory, gjf.getFileName());
            if (targetFile.exists()) {
                if (shellCallback.isMergeSupported()) {
                    source = shellCallback.mergeJavaFile(gjf
                                    .getFormattedContent(), targetFile
                                    .getAbsolutePath(),
                            MergeConstants.OLD_ELEMENT_TAGS,
                            gjf.getFileEncoding());
                } else if (shellCallback.isOverwriteEnabled()) {
                    source = gjf.getFormattedContent();

                } else {
                    source = gjf.getFormattedContent();
                    targetFile = getUniqueFileName(directory, gjf
                            .getFileName());

                }
            } else {
                source = gjf.getFormattedContent();
            }

            writeFile(targetFile, source, gjf.getFileEncoding());
        } catch (ShellException e) {
//            warnings.add(e.getMessage());
        }
    }

    private void writeFile(File file, String content, String fileEncoding) throws IOException {
        FileOutputStream fos = new FileOutputStream(file, false);
        OutputStreamWriter osw;
        if (fileEncoding == null) {
            osw = new OutputStreamWriter(fos);
        } else {
            osw = new OutputStreamWriter(fos, fileEncoding);
        }

        BufferedWriter bw = new BufferedWriter(osw);
        bw.write(content);
        bw.close();
    }

    private File getUniqueFileName(File directory, String fileName) {
        File answer = null;

        // try up to 1000 times to generate a unique file name
        StringBuilder sb = new StringBuilder();
        for (int i = 1; i < 1000; i++) {
            sb.setLength(0);
            sb.append(fileName);
            sb.append('.');
            sb.append(i);

            File testFile = new File(directory, sb.toString());
            if (!testFile.exists()) {
                answer = testFile;
                break;
            }
        }

        if (answer == null) {
            throw new RuntimeException("获取文件出错"); //$NON-NLS-1$
        }

        return answer;
    }
}
